#include "device.h"
//昂瑞微的驱动库API
#include "rwip_config.h" // RW SW configuration
#include "peripheral.h"
#include "eeprom_ota.h"
#define ee_ota_log(format, ...) __OSAL_LOG("[eeprom_ota.c] " format "\r\n", ##__VA_ARGS__)

#define EE_OAT_FLASH_START_ADDR (OTA_CODE_ADDR & 0xfffff) // flash起始地址
#define EE_OAT_FLASH_SIZE APP_FLASH_SIZE				  // OTA CODE SIZE
#define EE_OAT_FLASH_SECTOR_SIZE 4096					  // flash扇区大小

static uint8_t debug_enable = 0;
static uint8_t free_sector = 0xFF; //空闲扇区

inline static void ee_oat_mutex_lock(void)
{
	Device_EnterCritical();
}

inline static void ee_oat_mutex_unlock(void)
{
	Device_ExitCritical();
}

//读操作
inline static int ee_ota_read_flash(uint32_t addr, uint8_t *data, uint32_t len)
{
	// ee_ota_log("read add:%08X,len:%d", addr, len);
	sf_read(HS_SF, 0, EE_OAT_FLASH_START_ADDR + addr, data, len);
	return 0;
}

//写操作
inline static int ee_ota_write_flash(uint32_t addr, uint8_t *data, uint32_t len)
{
	// ee_ota_log("write add:%08X,len:%d", addr, len);
	sf_write(HS_SF, 0, EE_OAT_FLASH_START_ADDR + addr, data, len);
	return 0;
}

//擦除操作
inline static int ee_ota_erase_sector(uint32_t addr)
{
	ee_ota_log("erase add:%08X", addr);
	sf_erase(HS_SF, 0, EE_OAT_FLASH_START_ADDR + addr, 4 * 1024);
	return 0;
}

//! /////////////////////////////////////////////////////////////////////////////////////////////////////////
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////

//擦除EEPROM OTA全部数据：成功返回0
int eeprom_ota_erase_all(void)
{
	ee_ota_log("ota erase all");
	ee_oat_mutex_lock();
	sf_erase(HS_SF, 0, EE_OAT_FLASH_START_ADDR, EE_OAT_FLASH_SIZE);
	ee_oat_mutex_unlock();
	return 0;
}
//读EEPROM：成功返回0
int eeprom_ota_read(uint32_t addr, uint8_t *data, uint32_t len)
{
	ee_oat_mutex_lock();
	ee_ota_read_flash(addr, data, len);
	ee_oat_mutex_unlock();
	return 0;
}

/**写EEPROM：成功返回0（初始化时，必须擦掉空闲扇区）
 * @brief
 *
 * @param [in] addr
 * @param [in] data
 * @param [in] len
 * @return int
 *
 * @note
 */
int eeprom_ota_write(uint32_t addr, uint8_t *data, uint32_t len)
{
	uint32_t secpos;		 // 扇区地址
	uint32_t NumByteToWrite; //写入数据总长度
	uint16_t secoff;		 // 在扇区内的偏移
	uint16_t secremain;		 // 扇区剩余空间大小
	uint16_t i = 0;
	uint8_t tmp[EE_OAT_FLASH_SECTOR_SIZE];
	NumByteToWrite = len;
	secpos = addr & (~(EE_OAT_FLASH_SECTOR_SIZE - 1)); // 扇区地址
	secoff = addr & (EE_OAT_FLASH_SECTOR_SIZE - 1);	   // 在扇区内的偏移
	secremain = EE_OAT_FLASH_SECTOR_SIZE - secoff;	   // 扇区剩余空间大小
	ee_oat_mutex_lock();							   //
	if (NumByteToWrite <= secremain)				   //
		secremain = NumByteToWrite;					   // 不大于4096个字节
	while (1)
	{
		ee_ota_read_flash(secpos, tmp, EE_OAT_FLASH_SECTOR_SIZE); // 读出整个扇区

		for (i = 0; i < secremain; i++)
		{
			// 校验数据
			if (tmp[secoff + i] != 0XFF)
				break; // 需要擦除
		}

		if (i < secremain)
		{
			// 需要擦除
			ee_ota_erase_sector(secpos); // 擦除这个扇区

			for (i = 0; i < secremain; i++)
			{
				// 复制
				tmp[i + secoff] = data[i];
			}

			ee_ota_write_flash(secpos, tmp, EE_OAT_FLASH_SECTOR_SIZE); // 写入整个扇区
		}
		else
		{
			ee_ota_write_flash(addr, data, secremain); // 写已经擦除了的,直接写入扇区剩余区间.
		}

		if (NumByteToWrite == secremain) // 写入结束了
			break;
		else
		{
			secpos += EE_OAT_FLASH_SECTOR_SIZE;
			secoff = 0;					 // 偏移位置为0
			data += secremain;			 // 指针偏移
			addr += secremain;			 // 写地址偏移
			NumByteToWrite -= secremain; // 字节数递减

			if (NumByteToWrite > EE_OAT_FLASH_SECTOR_SIZE)
				secremain = EE_OAT_FLASH_SECTOR_SIZE; // 下一个扇区还是写不完
			else
				secremain = NumByteToWrite; // 下一个扇区可以写完了
		}
	}
	ee_oat_mutex_unlock();
	return 0;
}
